﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using BearUtil;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using UnityEditor;
using UnityEngine;

namespace BearUtil
{
    /// <summary>
    /// Excel 文本导入类
    /// </summary>
    public class ExcelDataGenerator : GlobalConfig<ExcelDataGenerator>, ICustomSetting
    {
        [LabelText("ExcelData输出存储地址"), FolderPath, NonSerialized]
        public string ExcelDataPath = "Assets/StoryEditor/Excel/Datas";

        [LabelText("Stories输出存储地址"), HideLabel, Sirenix.OdinInspector.ReadOnly]
        public string StoriesDataPath = "Assets/StoryEditor/Excel/Datas/Stories";
        
        [LabelText("Excel输出存储地址"), FolderPath]
        public string OutputExcelFold;
        
        [Header("依赖文件路径"), LabelText("文件列表")]
        public List<ExcelDataAdapter> adapters;
        
        #region Setting
        
        public string AddName {
            get
            {
                return "新增";
            }
            set { }
        }
        public string RemoveName { 
            get 
            {
                return "删减"; 
            }
            set { }
        }
        public void Add(OdinMenuEditorWindow window)
        {
            // throw new System.NotImplementedException();
            if (adapters == null)
                adapters = new List<ExcelDataAdapter>();
            
            adapters.Add(new ExcelDataAdapter());
        }

        public void Remove(OdinMenuItem selected)
        {
            if (adapters == null)
                adapters = new List<ExcelDataAdapter>();
            
            adapters.RemoveAt(adapters.Count() - 1);
        }
    
#endregion

        /// <summary>
        /// 生成 ExcelData
        /// </summary>
        /// <param name="datas"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static ExcelData GenerateExcelData<T>(List<T> datas)
        {
            if (datas == null || datas.Count() <= 0)
                return null;
            
            Dictionary<Vector2Int, string> result = new Dictionary<Vector2Int, string>();

            int row = 3;
            int col = 0;
            // 设置 excel 模板内容
            var tmp = datas[0];
            var fields = tmp.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (var f in fields)
            {
                var paramName = new Vector2Int(col, 0);
                var paramType = new Vector2Int(col, 1);
                var paramDes = new Vector2Int(col, 2);
                result.Add(paramName, f.Name);
                string valueTypeName = f.FieldType.Name.ToLower();
                switch (valueTypeName)
                {
                    case "nodetype":
                    case "int32":
                        result.Add(paramType, "int");
                        break;
                    case "int32[]":
                        result.Add(paramType, "int[]");
                        break;
                    case "int32[][]":
                        result.Add(paramType, "int[][]");
                        break;
                    case "boolean":
                        result.Add(paramType, "bool");
                        break;
                    case "single":
                        result.Add(paramType, "float");
                        break;
                    default:
                        result.Add(paramType, valueTypeName);
                        break;
                }
                
                // 获取注释
                var attributes = (DescriptionAttribute[])(f.GetCustomAttributes(typeof(DescriptionAttribute), false));
                if (attributes != null && attributes.Length > 0)
                    result.Add(paramDes, attributes[0].Description);
                else 
                    result.Add(paramDes, "");

                col++;
            }
            
            // 填充 data 
            for (int i = 0; i < datas.Count(); i++)
            {
                col = 0;
                var data = datas[i];
                foreach (var f in fields)
                {
                    var paramPos = new Vector2Int(col, i + 3);
                    var paramValue = f.GetValue(data);

                    if (paramValue != null)
                    {
                        var typeName = paramValue.GetType().Name.ToLower();
                        switch (typeName)
                        {
                            case "int32[][]":
                                var children = (paramValue as int[][]);
                                StringBuilder v1 = new StringBuilder(); 
                                for (int j = 0; j < children.Length; j++)
                                {
                                    var ns = children[j];
                                    for (int k = 0; k < ns.Length; k++)
                                    {
                                        v1.Append(ns[k]);
                                        if (k + 1 < ns.Length)
                                            v1.Append("#");
                                    }
                                    
                                    if (j + 1 < children.Length)
                                        v1.Append("|");
                                }
                                result.Add(paramPos, v1.ToString());
                                break;
                            case "string[]":
                                var strs = (paramValue as string[]);
                                
                                if (strs == null)
                                {
                                    result.Add(paramPos, "");
                                    break;
                                }
                                
                                StringBuilder v2 = new StringBuilder();
                                for (int j = 0; j < strs.Length; j++)
                                {
                                    v2.Append(strs[j]);
                                    if(j + 1 < strs.Length)
                                        v2.Append("#");
                                }
                                result.Add(paramPos, v2.ToString());
                                break;
                            case "int32[]":
                                var ints = (paramValue as int[]);

                                if (ints == null)
                                {
                                    result.Add(paramPos, "");
                                    break;
                                }

                                StringBuilder v3 = new StringBuilder();
                                for (int j = 0; j < ints.Length; j++)
                                {
                                    v3.Append(ints[j]);
                                    if(j + 1 < ints.Length)
                                        v3.Append("#");
                                }
                                result.Add(paramPos, v3.ToString());
                                break;
                            case "nodetype":
                                result.Add(paramPos, ((int)paramValue).ToString());
                                break;
                            default:
                                result.Add(paramPos, paramValue.ToString());
                                break;
                        }
                    }
                    else
                        result.Add(paramPos, "");
                    col++;
                }
                // 换行
                row++;
            }
            
            var excel = ScriptableObject.CreateInstance<ExcelData>();
            excel.Assemble(result, row, col);

            return excel;
        }
        
        /// <summary>
        /// 输出最终 Excel 文件
        /// </summary>
        public static void GenerateStoryData()
        {
            // 文件完整路径
            var path = Application.dataPath.Replace("Assets", "") + 
                       ExcelDataGenerator.Instance.StoriesDataPath;
            // var a = AssetDatabase.LoadAssetAtPath<ExcelData>(path + "/FirstStory.asset");
            var paths = Directory.GetFiles(path);
            List<ExcelData> datas = new List<ExcelData>();
            
            // 获取 asset
            for (int i = 0; i < paths.Length; i++)
            {
                var filePath = ExcelDataGenerator.Instance.StoriesDataPath + "/" + Path.GetFileName(paths[i]);
                var data = AssetDatabase.LoadAssetAtPath<ExcelData>(filePath);
                if (data == null)
                    continue;
                datas.Add(data);
            }

            if (datas == null || datas.Count <= 0)
                return;
            
            int offsetRow = 3;
            int col = datas[0].col;
            int row = datas[0].row;
            for (int i = 1; i < datas.Count; i++)
            {
                row += datas[i].row - offsetRow;
            }

            int r = 0;
            var exDatas = new string[col, row];
            for (int i = 0; i < datas.Count; i++)
            {
                var data = datas[i];
                data.LoadTransformData();
                for (int x = 0; x < data.col; x++)
                {
                    // 合并数据需求 i == 0 是从 0 开始
                    for (int y = i == 0 ? 0 : 3; y < data.row; y++)
                    {
                        exDatas[x, r + y] = data.Datas[x, y];
                    }
                }

                r += data.row - 3;
            }

            ExcelData newData = new ExcelData();
            newData.col = col;
            newData.row = row;
            newData.name = "dialogue";
            newData.sheetName = "dialogue";
            newData.SaveData(exDatas);
            newData.LoadTransformData();
            ExcelEdit.WriteExcel(newData, ExcelDataGenerator.Instance.OutputExcelFold);
        }
    }
    
    [Serializable]
    public class ExcelDataAdapter
    {
        [Sirenix.OdinInspector.FilePath, InlineButton("CheckExcel"), InlineButton("Generate")]
        public string FilePath;

        [BoxGroup("生成独立数据")]
        public string FileName = "";
        [BoxGroup("生成独立数据"), InlineButton("RemoveData"), InlineButton("AddData"), DisableIf("FilePath")]
        public ExcelData Data;

        [ShowIf("FilePath")]
        public List<ExcelData> Datas;
        
        /// <summary>
        /// 生成 Excel 内容数据，每一个 Sheet 是一个 ExcelData
        /// </summary>
        [EnableIf("FilePath")]
        public void Generate()
        {
            if (!FilePath.HasFile())
            {
                Debug.LogError("不存在对应文件");
                return;
            }

            ExcelEdit.LoadExcel(FilePath, ref Datas);
            string excelName = Path.GetFileNameWithoutExtension(FilePath);
            foreach (var excelData in Datas)
            {
                Utils.CreateScriptableObject<ExcelData>(
                    excelData, 
                    ExcelDataGenerator.Instance.ExcelDataPath + "/" + Path.GetFileNameWithoutExtension(FilePath), 
                    excelName + "_" + excelData.sheetName
                    );
            }
        }

        [EnableIf("FilePath")]
        public void CheckExcel()
        {
            if (FilePath == null || FilePath.Equals(""))
                return;

            ExcelViewWindow.OpenWindow(FilePath);
        }

        /// <summary>
        /// 创建独立 Excel 文本数据
        /// </summary>
        public void AddData()
        {
            if (FileName.Equals(""))
            {
                Debug.LogWarning("缺少创建文件名称");
                return;
            }

            // 填入参数
            var ed = new ExcelData();
            ed.col = 1;
            ed.row = 1;
            ed.sheetName = "newData";
            ed.SaveData(new string[1,1]{{""}});
            Utils.CreateScriptableObject<ExcelData>(ed, ExcelDataGenerator.Instance.ExcelDataPath, FileName);
            Data = ed;
        }
        
        /// <summary>
        /// 删除独立数据
        /// </summary>
        public void RemoveData()
        {
            if (Data == null)
                return;
            
            Data.DeleteSelf();
        }
    }   
}